import backtrader as bt  
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt

from backtrader_plotting import Bokeh
from backtrader_plotting.schemes import Tradimo

# 读取csv
data = pd.read_csv('法宝回测/data/sh1.csv') # 股票日数据
ttg_data = pd.read_csv('法宝回测/data/bwwmacd.csv') # 股票指标数据(大智慧导出)


# 创建股票数据源
data_source = bt.feeds.PandasData(dataname=data)

# 创建Cerebro引擎
cerebro = bt.Cerebro()

# 添加股票数据源到引擎
cerebro.adddata(data_source)

# 添加TTG指标
ttg = bt.indicators.TrueTrendGraph(smoothing=10, plot=True)
cerebro.addindicator(ttg, 'TTG', barplot=True)

# 创建策略类
class MyStrategy(bt.Strategy):
    params = dict(
        # 可以添加一些参数
    )

    def __init__(self):
        # 这里可以添加一些初始化代码
        pass

    def next(self):
        # 交易逻辑
        pass

# 添加策略到引擎
cerebro.addstrategy(MyStrategy)

# 运行回测
cerebro.run()

# 绘制图形
cerebro.plot()




'''
`cerebro.addindicator`方法是用来添加自定义指标到Cerebro引擎中的。这个方法的常见用法如下：

- `ttg`: 这是你创建的指标实例，比如`TrueTrendGraph`指标。
- `'TTG'`: 这是指标的名称，用于在图表上标识这个指标。
- `barplot=True`: 这个参数指定了指标的显示方式。当设置为`True`时，指标将以条形图的形式显示在图表上。这通常用于显示如成交量这样的数据，或者任何你希望以条形图形式展示的指标。

例如，如果你有一个`TrueTrendGraph`指标，并且你希望在图表上以条形图的形式展示它，你可以这样写：

```python
ttg = bt.indicators.TrueTrendGraph(smoothing=10)
cerebro.addindicator(ttg, 'TTG', barplot=True)
```

然而，需要注意的是，`TrueTrendGraph`指标本身并不是设计为以条形图显示的，它通常用于生成一个趋势线，可能更适合用线图来展示。如果你想要将TTG指标以线图的形式展示，你应该省略`barplot=True`参数或者将其设置为`False`：

```python
ttg = bt.indicators.TrueTrendGraph(smoothing=10)
cerebro.addindicator(ttg, 'TTG')
```

这样，`TTG`指标将以线图的形式显示在图表上。

如果你有一个外部的TTG指标数据，并且想要将其作为指标添加到图表上，
你需要首先确保这个数据可以被Backtrader识别。
通常，这意味着你需要将外部数据转换为Backtrader的`DataFeed`对象，
然后使用`addindicator`方法添加到图表上。
如果你的TTG数据是作为单独的CSV文件提供的，
你可能需要自定义一个数据源来读取这个CSV文件，并将其作为指标添加到图表上。

在Backtrader中，如果你想要自定义一个指标，比如一个名为`TrueTrendGraph`的指标，
你需要继承自`bt.Indicator`类，并实现必要的方法。自定义指标通常需要实现以下几个方法：

- `__init__`: 构造函数，用于初始化指标。
- `next()`: 计算指标的下一个值。
- `plot()`: 可选，定义如何将指标绘制到图表上。

以下是一个简单的自定义指标示例，展示了如何创建一个名为`TrueTrendGraph`的指标。
请注意，这个示例是一个框架，你需要根据TTG指标的具体计算逻辑来填充`next()`方法的实现细节。

```python
import backtrader as bt

class TrueTrendGraph(bt.Indicator):
    lines = ('ttg',)  # 指标名称
    params = dict(
        smoothing=10,  # 假设有一个平滑参数
    )

    def __init__(self):
        super(TrueTrendGraph, self).__init__()
        self.ttg = bt.indicators.SimpleMovingAverage(self.data, period=self.params.smoothing)

    def next(self):
        # 这里实现TTG指标的计算逻辑
        # 以下仅为示例，需要根据TTG的具体计算方法来实现
        self.ttg[0] = self.data.close  # 假设TTG就是简单移动平均

    def plot(self):
        # 定义如何绘制指标
        if self.ttg:
            self.plotline(self.ttg, 'ttg', 'TTG Line', color='red')

# 使用自定义指标
data = bt.feeds.PandasData(dataname=pd.DataFrame(...))
cerebro = bt.Cerebro()
cerebro.adddata(data)

# 添加自定义指标
ttg_indicator = TrueTrendGraph()
cerebro.addindicator(ttg_indicator, 'ttg')

# 运行回测
cerebro.run()

# 绘制图表
cerebro.plot()
```

在上面的代码中，`TrueTrendGraph`类继承自`bt.Indicator`，并且定义了一个`ttg`属性作为指标的输出。`__init__`方法中，我们初始化了一个简单移动平均作为示例，但你需要根据TTG指标的具体逻辑来实现`next()`方法。

`plot()`方法定义了如何在图表上绘制这个指标，这里我们使用了`plotline`方法来绘制一条线。

请注意，这个示例并没有实现TTG指标的具体逻辑，因为TTG不是一个标准的技术指标，你需要提供或者查找TTG的具体计算方法。如果你有TTG的计算公式或者逻辑，你可以在`next()`方法中实现它。如果你需要进一步的帮助来实现TTG指标的具体逻辑，请提供更多的信息。


在Python中，`super()`函数用于调用父类（超类）的初始化方法。当你创建一个子类并希望调用其父类的构造函数时，这非常有用。这确保了父类被正确初始化，任何父类中定义的初始化逻辑都将被执行。

在你提到的代码片段中：

```python
super(TrueTrendGraph, self).__init__()
```

这行代码调用了`TrueTrendGraph`类的父类（在这个情况下是`bt.Indicator`）的构造函数。这里的`TrueTrendGraph`是当前类，`self`代表当前类的实例，`__init__`是构造函数。

- `TrueTrendGraph`: 当前类名。
- `self`: 当前类的实例。
- `__init__`: 被调用的父类构造函数。

这种调用方式是Python 2和Python 3中推荐的调用父类构造函数的方法，因为它可以确保在多重继承的情况下正确地调用父类的构造函数。

在Backtrader的`Indicator`类中，`__init__`方法可能执行一些初始化操作，比如设置存储指标值的数组或初始化一些参数。通过调用`super().__init__()`，你确保了这些父类中的初始化操作也被执行。

在Python 3中，你也可以使用更简洁的写法：

```python
super().__init__()
```

这与上面提到的写法等效，但是它不需要显式指定类名，因为Python 3会自动推断`super()`应该调用哪个父类的构造函数。如果你的代码需要兼容Python 2和Python 3，使用显式的类名是更好的选择。


当然可以。以下是一个详细的示例，展示如何将外部CSV格式的数据源作为自定义指标添加到Backtrader图表上。在这个例子中，我们假设CSV文件包含两列数据：日期和指标值。我们将创建一个自定义数据源类来读取CSV文件，并将其作为指标添加到图表上。

首先，确保你已经安装了`backtrader`和`pandas`库。如果没有安装，请使用以下命令安装：

```bash
pip install backtrader pandas
```

然后，使用以下代码：


import backtrader as bt
import pandas as pd
from datetime import datetime

# 定义一个自定义数据源类
class ExternalCSVData(bt.feeds.PandasData):
    def __init__(self, csvfile, **kwargs):
        super(ExternalCSVData, self).__init__(dataname=pd.read_csv(csvfile, parse_dates=['Date'], index_col='Date'), **kwargs)

# 定义一个自定义指标类
class ExternalIndicator(bt.Indicator):
    lines = ('ext_ind',)  # 指标名称
    params = dict(
        src_data=None,  # 外部数据源
    )

    def __init__(self):
        super(ExternalIndicator, self).__init__()
        self.addminperiod(self.params.src_data.window)  # 确保有足够的数据

    def next(self):
        # 这里实现指标的计算逻辑
        # 假设外部数据源的指标值存储在'IndicatorValue'列
        self.lines.ext_ind[0] = self.params.src_data.lines.IndicatorValue[0]

# 读取CSV文件
csvfile = 'path_to_your_external_data.csv'  # 替换为外部数据CSV文件的路径
external_data = ExternalCSVData(csvfile)

# 创建Cerebro引擎
cerebro = bt.Cerebro()

# 添加外部数据源到引擎
cerebro.adddata(external_data)

# 创建自定义指标
ext_ind = ExternalIndicator(src_data=external_data)

# 将自定义指标添加到数据源
cerebro.addindicator(ext_ind, 'ext_ind')

# 创建一个简单的策略
class SimpleStrategy(bt.Strategy):
    def next(self):
        # 简单的交易逻辑
        if self.indicators.ext_ind > 0:  # 假设指标值大于0时买入
            self.buy()
        elif self.indicators.ext_ind < 0:  # 指标值小于0时卖出
            self.sell()

# 添加策略到引擎
cerebro.addstrategy(SimpleStrategy)

# 运行回测
cerebro.run()

# 绘制图表
cerebro.plot()
```

在这个示例中，我们首先定义了一个`ExternalCSVData`类，它继承自`bt.feeds.PandasData`，用于读取CSV文件并将其作为数据源。然后，我们定义了一个`ExternalIndicator`类，它继承自`bt.Indicator`，用于将外部数据源的指标值作为自定义指标。

请注意，你需要根据你的CSV文件的具体格式和指标的计算逻辑来调整`ExternalCSVData`和`ExternalIndicator`类的实现。例如，如果CSV文件的日期列名为`Date`，指标值列名为`IndicatorValue`，请确保在代码中使用正确的列名。

最后，我们创建了一个简单的策略`SimpleStrategy`，它使用自定义指标来决定买入或卖出。然后，我们将数据源、指标和策略添加到Cerebro引擎中，运行回测，并绘制图表。


'''